package edu.uwm.cs552.gfx;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.net.URL;

import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.bridge.ViewBox;
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.util.XMLResourceDescriptor;
import org.w3c.dom.svg.SVGAnimatedRect;
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGSVGElement;


/**
 * Facade class to covert a SVG file to a Java Image.
 * Thanks to Jonathan Johnson.
 * <a href="http://mail-archives.apache.org/mod_mbox/xmlgraphics-batik-users/200601.mbox/%3CAD922568C8E1C546B98A94DB60C5403AFB65C4@NELSON.labrat.com%3E">
 * Jonathan Johnson</a>.
 * I additionally fixed it so that it works also for non-identity viewport transformations;
 * if height and width weren't identical to pixels in the viewport, the original code
 * didn't work.
 */
public class SVGImageCreator implements Serializable {	
	/**
	 * Increment after an incompatible change
	 */
	private static final long serialVersionUID = 1L;

	private final URL url;
	
    /** Root node of svg document */
    private transient GraphicsNode rootSvgNode;

    /** Loaded SVG document */
    private transient SVGDocument svgDocument;

    /**
     * Load the svg resource from a URL into a document.
     * @param url location of svg resource.
     * @throws java.io.IOException when svg resource cannot be read.
     */
    public SVGImageCreator(URL url)
        throws IOException
    {
    	this.url = url;
        init();
    }

	private void init() throws IOException {
		String parser = XMLResourceDescriptor.getXMLParserClassName();
        SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(parser);
        svgDocument = (SVGDocument)factory.createDocument(url.toString());
        rootSvgNode = getRootNode(svgDocument);
	}
    
    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
    	stream.defaultReadObject();
    	init();
    }

    /**
     * Get svg root from the given document.
     *
     * @param document svg resource
     */
    private static GraphicsNode getRootNode(SVGDocument document)
    {
    	// Build the tree and get the document dimensions
    	UserAgentAdapter userAgentAdapter = new UserAgentAdapter();
    	BridgeContext bridgeContext = new BridgeContext(userAgentAdapter);
    	GVTBuilder builder = new GVTBuilder();

    	return builder.build(bridgeContext, document);
    }

    /**
     * Return the URL associated with this image creator.
     */
    public URL getURL() {
    	return url;
    }
    
    /**
     * Get the svg root node of the document.
     *
     * @return svg root node.
     */
    public GraphicsNode getRootSvgNode()
    {
        return rootSvgNode;
    }

    /**
     * Get the svg document.
     * @return the svg document.
     */
    public SVGDocument getSvgDocument()
    {
        return svgDocument;
    }

    /**
     * Renders and returns the svg based image.
     *
     * @param width desired width
     * @param height desired height
     * @return image of the rendered svg.
     */
    public Image getImage(int width, int height)
    {
    	System.out.println("width = " + width + ", height = " + height);
    	
        // Paint svg into image buffer
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = (Graphics2D) bufferedImage.getGraphics();

        // For a smooth graphic with no jagged edges or rastorized look.
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
            RenderingHints.VALUE_INTERPOLATION_BILINEAR);

        draw(g2d,width,height);

        // Cleanup and return image
        g2d.dispose();
        return bufferedImage;
    }

    public void draw(Graphics g, int width, int height) {
    	if (g instanceof Graphics2D) {
    		Graphics2D g2d = (Graphics2D)g;
    		AffineTransform current = g2d.getTransform();

            SVGSVGElement elt = svgDocument.getRootElement();
            final SVGAnimatedRect viewBox = elt.getViewBox();
            float viewWidth = viewBox.getBaseVal().getWidth();
            float viewHeight = viewBox.getBaseVal().getHeight();
            float svgWidth = elt.getWidth().getBaseVal().getValue();
            float svgHeight = elt.getHeight().getBaseVal().getValue();
           
        	UserAgentAdapter userAgentAdapter = new UserAgentAdapter();
        	BridgeContext bridgeContext = new BridgeContext(userAgentAdapter);
            AffineTransform usr2dev = ViewBox.getViewTransform(null, elt, width*viewWidth/svgWidth, height*viewHeight/svgHeight, bridgeContext);
            g2d.transform(usr2dev);

            rootSvgNode.paint(g2d);
            g2d.setTransform(current);
    	}
    }
}
